﻿using System;
using ActiveDirectoryUtilities.CommonLibrary;
using ActiveDirectoryUtilities.DirectoryServiceAccess;
using System.DirectoryServices.Protocols;
using System.Text;
using System.Reflection;
using System.Collections.Generic;

namespace ActiveDirectoryUtilities.FindGuidInAD
{
	class Program
	{

		// Fields
		private const string CMD_LINE_SWITCH_SHOW_ATTRIBUTES = "attr";
		private const string CMD_LINE_SWITCH_QUIET = "quiet";
		private static Guid _guidToSearchFor;
		private static bool _dumpObjectAttrs;
		private static bool _quietMode;

		static int Main(string[] args)
		{
			AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);


			if (parseCommandLine(args))
			{
				if (!_quietMode)
				{
					outputHeader();
				}

				Guid objectGuid = Guid.Empty;
				string schemaClass = GuidFinder.TranslateObjectTypeSchemaIDGuidToFriendlyName(_guidToSearchFor, out objectGuid);
				if (!string.IsNullOrEmpty(schemaClass) && string.Compare(schemaClass, _guidToSearchFor.ToString()) != 0)
				{
					if (!_quietMode)
					{
						Console.WriteLine("Schema Object Class:\t{0}", schemaClass);
						Console.WriteLine();
						adObject(objectGuid);
						return 0;
					}
					else
					{
						adObject(objectGuid);
						return 0;
					}

				}

				string extendedAccessRight = GuidFinder.TranslateExtendedRightGuidToFriendlyName(_guidToSearchFor, out objectGuid);
				if (!string.IsNullOrEmpty(extendedAccessRight) && string.Compare(extendedAccessRight, _guidToSearchFor.ToString()) != 0)
				{
					if (!_quietMode)
					{
						Console.WriteLine("Extended Access Right:\t{0}", extendedAccessRight);
						Console.WriteLine();
						adObject(objectGuid);
						return 0;
					}
					else
					{
						adObject(objectGuid);
						return 0;
					}
				}

				string objectDn = GuidFinder.TranslateCNOfGuidToDistinguishedName(_guidToSearchFor, out objectGuid);
				if (!string.IsNullOrEmpty(objectDn) && string.Compare(objectDn, _guidToSearchFor.ToString()) != 0)
				{
					adObject(objectGuid);
					return 0;
				}

				adObject(_guidToSearchFor);
				return 0;
			}

			Console.WriteLine("Nothing found.");
			Console.WriteLine("This searches schema, extended access rights, objectGuid attribute, and commonName (CN) for the GUID.  If you have another location you'd like to search, please post your request at http://www.codeplex.com/ActiveDirectoryUtils.");
			return 1;
		}

		static private void adObject(Guid guidToSearchFor)
		{
			string adObject = GuidFinder.TranslateObjectGuidToDistingushedName(guidToSearchFor);
			if ((!string.IsNullOrEmpty(adObject) && (string.Compare(adObject, guidToSearchFor.ToString()) != 0)))
			{
				if (!_quietMode)
				{
					Console.WriteLine("AD Object:\t\t{0}", adObject);
					if (_dumpObjectAttrs)
					{
						Console.WriteLine();
						outputObjectAttributes(adObject);
					}
				}
				else
				{
					Console.WriteLine(adObject);
					if (_dumpObjectAttrs)
					{
						Console.WriteLine();
						outputObjectAttributes(adObject);
					}
				}
			}
		}

		static private bool parseCommandLine(string[] args)
		{
			bool result;
			if (args.Length >= 1)
			{
				for (int i = 0; i < args.Length; i++)
				{
					string text = args[i];
					bool flag = false;
					if (text.Substring(0, 1).CompareTo("/") == 0 || text.Substring(0, 1).CompareTo("-") == 0)
					{
						if (string.Compare(text.Substring(1), "attr", StringComparison.OrdinalIgnoreCase) == 0
							|| string.Compare(text.Substring(1), "a", StringComparison.OrdinalIgnoreCase) == 0)
						{
							Program._dumpObjectAttrs = true;
							flag = true;
						}
						else
						{
							if (string.Compare(text.Substring(1), "quiet", StringComparison.OrdinalIgnoreCase) == 0
								|| string.Compare(text.Substring(1), "q", StringComparison.OrdinalIgnoreCase) == 0)
							{
								Program._quietMode = true;
								flag = true;
							}
						}
					}
					else
					{
						try
						{
							Program._guidToSearchFor = new Guid(text);
							flag = true;
						}
						catch (FormatException)
						{
							Console.WriteLine("Incorrect Guid format, please try again.\r\n");
							result = Program.outputHelp(text);
							return result;
						}
					}
					if (!flag)
					{
						Program.outputHelp(text);
						result = false;
						return result;
					}
				}
			}
			result = true;
			return result;
		}

		static private bool outputHelp(string incorrectSyntax)
		{
			outputHeader();

			if (!(string.IsNullOrEmpty(incorrectSyntax)))
			{
				Console.WriteLine("Incorrect	:  {0}", incorrectSyntax);
				Console.WriteLine();
			}
			Console.WriteLine("Translate an AD related Guid into a friendly name.  From http://www.codeplex.com/ActiveDirectoryUtils");
			Console.WriteLine("Command Line Options:  " + Assembly.GetExecutingAssembly().GetName().Name + " <" + System.Guid.Empty.ToString() + "> [/" + CMD_LINE_SWITCH_SHOW_ATTRIBUTES + "] [/" + CMD_LINE_SWITCH_QUIET + "]");
			Console.WriteLine();
			Console.WriteLine(" /attr  - Dump the attributes on the object.");
			Console.WriteLine(" /quiet - Output only the results (no header or descriptive information).");
			Console.WriteLine();
			Console.WriteLine("Example syntax:");
			Console.WriteLine(Assembly.GetExecutingAssembly().GetName().Name + " " + System.Guid.Empty.ToString());
			return false;
		}

		private static void outputHeader()
		{
			Console.WriteLine("Find objects referred to by a Guid in AD.  From http://www.codeplex.com/ActiveDirectoryUtils");
			Console.WriteLine("Version:  {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
			Console.WriteLine();
		}

		private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
		{
			Console.Clear();
			Console.WriteLine("This has experienced a critical error.  Please submit the below information to:\n http://www.codeplex.com/ActiveDirectoryUtils.");
			Console.WriteLine();
			outputHeader();
			Console.WriteLine(".NET Version: {0}", Environment.Version.ToString());
			Exception err = (Exception)e.ExceptionObject;
			Console.WriteLine("Type of Exception:\t{0}", err.GetType());
			Console.WriteLine("Error Message:\t{0}", err.Message);
			//Console.WriteLine("Stack Trace:\n{0}", err.StackTrace);
		}

		private static void outputObjectAttributes(string objectDn)
		{
			WLdapSearchRequest wLdapSearchRequest = new WLdapSearchRequest(string.Empty, (int)LDAP_PORTS.Global_Catalog, objectDn, "(objectClass=*)", SearchScope.Base, null);
			SearchResultEntry searchResultEntry;
			try
			{
				searchResultEntry = wLdapSearchRequest.FindOne();
			}
			catch (LdapException ex)
			{
				Console.WriteLine(ex.Message);
				return;
			}
			catch (DirectoryException ex2)
			{
				Console.WriteLine(ex2.Message);
				return;
			}
			if (searchResultEntry != null)
			{
				List<string> attributesReturned = new List<string>();
				int maxLength = 0;
				foreach (DirectoryAttribute directoryAttribute in searchResultEntry.Attributes.Values)
				{
					attributesReturned.Add(directoryAttribute.Name);
					Console.WriteLine(directoryAttribute.Name);
					if (directoryAttribute.Name.Length > maxLength)
					{
						maxLength = directoryAttribute.Name.Length;
					}
				}
				attributesReturned.Sort();

				foreach (string attributeName in attributesReturned)
				{
					StringBuilder stringBuilder = new StringBuilder();
					Console.Write("{0}", attributeName);
					for (int i = 0; i < maxLength - attributeName.Length; i++)
					{
						stringBuilder.Append(" ");
					}

					if (searchResultEntry.Attributes[attributeName][0].GetType() != typeof(byte[]))
					{

						Console.WriteLine("{0} - {1}", stringBuilder.ToString(), searchResultEntry.Attributes[attributeName][0]);
					}
					else
					{
						try
						{
							Console.WriteLine("{0} - {1}", stringBuilder.ToString(), new Guid((byte[])searchResultEntry.Attributes[attributeName][0]).ToString("B"));
						}
						catch (ArgumentException)
						{
							Console.WriteLine("{0} - {1}", stringBuilder.ToString(), BitConverter.ToString(((byte[])searchResultEntry.Attributes[attributeName][0])));
						}
					}

					if (searchResultEntry.Attributes[attributeName][0].GetType() != typeof(byte[]))
					{
						stringBuilder = new StringBuilder();
						for (int j = 0; j < maxLength + 3; j++)
						{
							stringBuilder.Append(" ");
						}
						for (int i = 1; i < searchResultEntry.Attributes[attributeName].Count; i++)
						{
							Console.WriteLine("{0}{1}", stringBuilder.ToString(), searchResultEntry.Attributes[attributeName][i]);
						}
					}
					else
					{
						stringBuilder = new StringBuilder();
						for (int j = 0; j < maxLength + 3; j++)
						{
							stringBuilder.Append(" ");
						}
						for (int i = 1; i < searchResultEntry.Attributes[attributeName].Count; i++)
						{
							try
							{
								Console.WriteLine("{0} - {1}", stringBuilder.ToString(), new Guid((byte[])searchResultEntry.Attributes[attributeName][i]).ToString("B"));
							}
							catch (ArgumentException)
							{
								Console.WriteLine("{0} - {1}", stringBuilder.ToString(), BitConverter.ToString(((byte[])searchResultEntry.Attributes[attributeName][i])));
							}
						}
					}
				}
			}
		}
	}
}
